package org.example.ag_notes.service;

import org.example.ag_notes.config.JwtProperties;
import org.example.ag_notes.dto.auth.LoginRequest;
import org.example.ag_notes.dto.auth.RegisterRequest;
import org.example.ag_notes.dto.auth.AuthResponse;
import org.example.ag_notes.dto.response.Response;
import org.example.ag_notes.entity.User;

import org.example.ag_notes.exception.AuthenticationException;
import org.example.ag_notes.repository.UserRepository;
import org.example.ag_notes.security.JwtTokenProvider;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional
public class AuthService {

    private final UserRepository userRepository;
    private final PasswordEncoder passwordEncoder;
    private final JwtTokenProvider jwtTokenProvider;
    private final JwtProperties jwtProperties;

    @Autowired
    public AuthService(UserRepository userRepository,
                       PasswordEncoder passwordEncoder,
                       JwtTokenProvider jwtTokenProvider,
                       JwtProperties jwtProperties) {
        this.userRepository = userRepository;
        this.passwordEncoder = passwordEncoder;
        this.jwtTokenProvider = jwtTokenProvider;
        this.jwtProperties = jwtProperties;
    }


    /**
     * 用户登录认证
     * @param request 登录请求
     * @return 认证响应(包含访问令牌和刷新令牌)
     */
    public AuthResponse login(LoginRequest request) {
        // 1. 验证用户是否存在
        User user = userRepository.findByUsername(request.getUsername())
                .orElseThrow(() -> new AuthenticationException("用户名或密码错误"));

        // 2. 验证密码
        if (!passwordEncoder.matches(request.getPassword(), user.getPassword())) {
            throw new AuthenticationException("用户名或密码错误");
        }

        // 3. 生成令牌
        String accessToken = jwtTokenProvider.generateAccessToken(user.getUsername());
        String refreshToken = jwtTokenProvider.generateRefreshToken(user.getUsername());
        user.setActive(true);
        userRepository.save(user);
        // 4. 返回响应
        return new AuthResponse(
                accessToken,
                refreshToken,
                jwtProperties.getAccessTokenExpirationMs() / 1000
        );
    }

    /**
     * 用户注册
     * @param request 注册请求
     */
    public Response<User> register(RegisterRequest request) {
        // 1. 检查用户名是否已存在
        if (userRepository.existsByUsername(request.getUsername())) {
            throw new DuplicateKeyException("用户名已存在");
        }

        // 2. 创建新用户
        User user = new User();
        user.setUsername(request.getUsername());
        user.setPassword(passwordEncoder.encode(request.getPassword()));

        // 3. 保存用户
        userRepository.save(user);

        // 使用静态工厂方法返回成功响应
        return Response.success("注册成功" , user);
    }

    /**
     * 刷新访问令牌
     * @param refreshToken 刷新令牌
     * @return 新的认证响应
     */
    public AuthResponse refreshToken(String refreshToken) {
        // 1. 验证刷新令牌
        if (!jwtTokenProvider.validateToken(refreshToken)) {
            throw new AuthenticationException("无效的刷新令牌");
        }

        // 2. 获取用户名并生成新令牌
        String username = jwtTokenProvider.getUsernameFromToken(refreshToken);
        String newAccessToken = jwtTokenProvider.generateAccessToken(username);

        // 3. 返回新访问令牌(不包含新刷新令牌)
        return new AuthResponse(
                newAccessToken,
                null,
                jwtProperties.getAccessTokenExpirationMs() / 1000
        );
    }

    /**
     * 用户注销
     * @param refreshToken 刷新令牌
     * @throws AuthenticationException 如果令牌无效或用户不存在
     */
    public void logout(String refreshToken , String accessToken) {
        // 1. 验证令牌格式有效性（快速失败）
        if (refreshToken == null || refreshToken.isBlank()) {
            throw new AuthenticationException("令牌不能为空");
        }

        // 2. 验证令牌签名和过期时间
        if (!jwtTokenProvider.validateToken(refreshToken)) {
            throw new AuthenticationException("无效的令牌");
        }

        // 3. 解析用户名（包含额外验证）
        String username = jwtTokenProvider.getUsernameFromToken(refreshToken);
        if (username == null || username.isBlank()) {
            throw new AuthenticationException("令牌中未包含有效用户信息");
        }

        // 4. 验证用户存在性
        User user = userRepository.findByUsername(username)
                .orElseThrow(() -> new AuthenticationException("用户不存在或已被删除"));

        // 5. 实现令牌失效机制（根据实际需求选择方案）
        user.setActive(false);
        userRepository.save(user);
    }

    /**
     * 验证Token有效性（供前端调用）
     * @param accessToken 访问令牌
     * @return 验证结果和用户信息
     */
    public Response<Boolean> validateToken(String accessToken) {
        try {
            // 1. 基础格式验证
            if (accessToken == null || !accessToken.startsWith("Bearer ")) {
                return Response.error(401,"Token格式错误");
            }

            // 提取实际Token（去掉Bearer前缀）
            String token = accessToken.substring(7);

            // 2. JWT签名和过期验证
            if (!jwtTokenProvider.validateToken(token)) {
                return Response.error(401,"Token已失效");
            }

            // 3. 获取用户名并验证用户状态
            String username = jwtTokenProvider.getUsernameFromToken(token);
            User user = userRepository.findByUsername(username)
                    .orElseThrow(() -> new AuthenticationException("用户不存在"));

            if (!user.isActive()) {
                return Response.error(403,"用户已被禁用");
            }

            // 4. 全部验证通过
            return Response.success("Token有效", true);

        } catch (Exception e) {
            return Response.error(403,"Token验证异常: " + e.getMessage());
        }
    }

    /**
     *
     * 根据前端的Token查用户ID
     * @param accessToken
     * @return 用户ID
     */
    public Integer getIDbyToken(String accessToken) {
        try {
            // 1. 基础格式验证
            if (accessToken == null || !accessToken.startsWith("Bearer ")) {
                return null;
            }

            // 提取实际Token（去掉Bearer前缀）
            String token = accessToken.substring(7);

            // 2. JWT签名和过期验证
            if (!jwtTokenProvider.validateToken(token)) {
                return null;
            }

            // 3. 获取用户名并验证用户状态
            String username = jwtTokenProvider.getUsernameFromToken(token);
            User user = userRepository.findByUsername(username)
                    .orElseThrow(() -> new AuthenticationException("用户不存在"));

            if (!user.isActive()) {
                return null;
            }

            // 4. 全部验证通过
            return user.getId();

        } catch (Exception e) {
            return null;
        }
    }

}